#ifndef PROCESSOR_H
#define PROCESSOR_H

#include <fstream>
#include <iostream>

#include "preq.h"
#include "processor_context.h"
#include "uarch/mreq.h"
#include "CaffProc/thread.h"
#include "uarch/stat.h"
#include "uarch/module.h"
#include "uarch/settings.h"
#include "uarch/types.h"
#include "uarch/stat_engine.h"

using namespace std;

typedef enum {
    SIMPLE_PROC = 0,
    IN_ORDER_PROC,
    OOO_PROC
} proc_type_t;

class processor : public Module {
public:
	processor(ModuleID moduleID, proc_type_t type = SIMPLE_PROC);
	~processor();

    LIST<Processor_context *> active_context_list;
    LIST<Processor_context *> free_context_list;
    LIST<Processor_context *> suspended_context_list;

    int free_contexts ();
    int active_contexts ();
    void assign_thread (Thread *thread);
    void remove_thread (Processor_context *context);

    Processor_stat_engine *stats;

    /** Debug.  */
    void dump_contexts ();
    
    // Inherited from module
    void tick ();
    void tock ();
};

class Processor_stat_engine : public Stat_engine
{
public:
    Processor_stat_engine (Module *m);
    Processor_stat_engine ();
    ~Processor_stat_engine ();
    
    // Stats
    Persistent_stat<counter_t> insn_count;
    Persistent_histogram_stat<counter_t> mem_latency_hist;
    Persistent_histogram_stat<counter_t> long_mem_latency_hist;
    Persistent_histogram_stat<counter_t> L1_miss_mem_latency_hist;
    Persistent_histogram_stat<counter_t> LSQ_dependence_delay;

    Persistent_stat<counter_t> load_count;
    Persistent_stat<counter_t> store_count;
    Persistent_stat<counter_t> ll_count;
    Persistent_stat<counter_t> sc_count;
    Persistent_stat<counter_t> sync_count;

    void global_stat_merge(Stat_engine * e);
    void clear_stats();
	void print_stats (ostream & out);

	void start_warmup ();
	void end_warmup ();	
	void save_samples ();
};

#endif   // PROCESSOR_H
